package com.egg.auth.controller.web;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.egg.auth.entity.menu.Menu;
import com.egg.auth.entity.role.Role;
import com.egg.auth.entity.role.RoleLinkMenu;
import com.egg.auth.enums.role.RoleAuthCodeEnum;
import com.egg.auth.enums.role.RoleDataScopeEnum;
import com.egg.auth.model.request.web.EnableListPatch;
import com.egg.auth.model.request.web.RoleLinkMenuPut;
import com.egg.auth.model.request.web.RolePostOrPut;
import com.egg.auth.model.response.web.RoleInfo;
import com.egg.auth.model.response.web.RoleMenuTree;
import com.egg.auth.model.response.web.RolePage;
import com.egg.auth.service.menu.IMenuService;
import com.egg.auth.service.role.IRoleLinkMenuService;
import com.egg.auth.service.role.IRoleService;
import com.egg.common.core.constant.CoreConstant;
import com.egg.common.core.model.controller.WebController;
import com.egg.common.core.model.response.OptionsResponse;
import com.egg.common.core.model.response.PageData;
import com.egg.common.core.model.response.ResponseData;
import com.egg.common.util.JsonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author east
 */
@Slf4j
@Api(tags = WebController.API_PREFIX + "角色中心")
@RestController
@RequestMapping("/role")
public class WebRoleController extends WebController {


    @Autowired
    private IRoleService roleService;
    @Autowired
    private IRoleLinkMenuService roleLinkMenuService;
    @Autowired
    private IMenuService menuService;


    @ApiOperation(value = "角色编码类型集合")
    @GetMapping(value = "/auth-code/option")
    public ResponseData<List<OptionsResponse>> roleCodeOptionGet() {
        List<RoleAuthCodeEnum> values = Arrays.stream(RoleAuthCodeEnum.values()).collect(Collectors.toList());
        List<OptionsResponse> optionList = new ArrayList<>();
        values.forEach(o -> {
            OptionsResponse option = new OptionsResponse();
            option.setValue(o.getCode());
            option.setLabel(o.getMessage());
            optionList.add(option);
        });
        return ResponseData.success(optionList);
    }

    @ApiOperation(value = "角色数据范围类型集合")
    @GetMapping(value = "/data-scope/option")
    public ResponseData<List<OptionsResponse>> roleDataScopeList() {
        List<RoleDataScopeEnum> values = Arrays.stream(RoleDataScopeEnum.values()).collect(Collectors.toList());
        List<OptionsResponse> optionList = new ArrayList<>();
        values.forEach(o -> {
            OptionsResponse option = new OptionsResponse();
            option.setValue(o.getCode());
            option.setLabel(o.getMessage());
            optionList.add(option);
        });
        return ResponseData.success(optionList);
    }

    @ApiOperation(value = "角色新增")
    @PostMapping
    public ResponseData<Long> rolePost(@RequestBody RolePostOrPut param) {
        Long id = roleService.add(param);
        return ResponseData.success(id);
    }

    @ApiOperation(value = "角色详情")
    @GetMapping("/{id}/info")
    public ResponseData<RoleInfo> roleInfoGet(@ApiParam(value = "角色ID") @PathVariable String id) {
        Role role = roleService.baseGetById(id);
        RoleInfo roleInfo = JsonUtil.objToObj(role, RoleInfo.class);
        roleService.fillDept(roleInfo);
        return ResponseData.success(roleInfo);
    }

    @ApiOperation(value = "角色编辑")
    @PutMapping("/{id}")
    public ResponseData<String> rolePut(@PathVariable String id, @RequestBody RolePostOrPut param) {
        roleService.put(id, param);
        return ResponseData.success(id);
    }

    @ApiOperation(value = "角色分页")
    @GetMapping("/page")
    public ResponseData<PageData<RolePage>> rolePageGet(
            @ApiParam(value = "页数", required = true) @RequestParam(value = "current", defaultValue = "1") Integer current
            , @ApiParam(value = "页长", required = true) @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize
            , @ApiParam(value = "关键字") @RequestParam(value = "keywords", required = false) String keywords
    ) {
        LambdaQueryWrapper<Role> qw = roleService.buildLambdaQw();
        qw.orderByAsc(Role::getSort);
        if (ObjectUtil.isNotEmpty(keywords)) {
            qw.and(wrapper ->
                    wrapper.like(Role::getName, keywords)
                            .or().like(Role::getAuthCode, keywords)
            );
        }
        Page<Role> dbPage = roleService.page(new Page<>(current, pageSize), qw);
        if (ObjectUtil.isEmpty(dbPage.getRecords())) {
            return ResponseData.success(new PageData<>(dbPage));
        }
        List<RolePage> list = JsonUtil.listToList(dbPage.getRecords(), RolePage.class);
        return ResponseData.success(new PageData<>(dbPage, list));
    }

    @ApiOperation(value = "角色下拉")
    @GetMapping("/option")
    public ResponseData<List<OptionsResponse>> roleOptionGet(
            @ApiParam(value = "角色名称") @RequestParam(value = "name", required = false) String name
    ) {
        LambdaQueryWrapper<Role> qw = roleService.buildLambdaQw();
        qw.orderByAsc(Role::getSort);
        if (ObjectUtil.isNotEmpty(name)) {
            qw.like(Role::getName, name);
        }
        List<Role> dbList = roleService.list(qw);
        List<OptionsResponse> optionList = new ArrayList<>();
        dbList.forEach(o -> {
            OptionsResponse option = new OptionsResponse();
            option.setValue(o.getId().toString());
            option.setLabel(o.getName());
            optionList.add(option);
        });
        return ResponseData.success(optionList);
    }

    @ApiOperation(value = "角色启用/禁用")
    @PatchMapping("/state/list")
    public ResponseData<String> roleStatePut(@RequestBody EnableListPatch param) {
        List<Role> list = roleService.baseFindById(param.getIds().stream()
                .filter(o -> ObjectUtil.isNotEmpty(o)).collect(Collectors.toSet()));
        list = list.stream()
                .filter(o -> !Objects.equals(o.getEnabled(), param.getEnable())).collect(Collectors.toList());
        if (ObjectUtil.isEmpty(list)) {
            return ResponseData.success();
        }
        List<Role> saveList = new ArrayList<>();
        list.forEach(o -> {
            Role user = new Role();
            user.setId(o.getId());
            user.setEnabled(param.getEnable());
            saveList.add(user);
        });
        roleService.baseEdit(saveList);
        return ResponseData.success();
    }

    @ApiOperation(value = "角色删除")
    @DeleteMapping
    public ResponseData<String> roleDel(
            @ApiParam(value = "ID集合", required = true) @RequestParam(value = "ids") Collection<String> ids
    ) {
        roleService.delRole(ids.stream().filter(o -> ObjectUtil.isNotEmpty(o)).collect(Collectors.toSet()));
        return ResponseData.success();
    }

    @ApiOperation(value = "角色关联菜单")
    @PutMapping("/{id}/link/menu")
    public ResponseData<String> roleLinkMenuPut(
            @ApiParam(value = "角色ID", required = true) @PathVariable String id
            , @RequestBody RoleLinkMenuPut put
    ) {
        roleLinkMenuService.putByRoleId(id, put);
        return ResponseData.success();
    }

    @ApiOperation(value = "角色菜单树")
    @GetMapping("/{id}/menu/tree")
    public ResponseData<List<RoleMenuTree>> roleMenuTreeGet(@ApiParam(value = "角色ID") @PathVariable String id) {
        List<Menu> menuList = menuService.findAll();
        if (ObjectUtil.isEmpty(menuList)) {
            return ResponseData.success(Collections.emptyList());
        }
        List<Menu> topList = menuList.stream()
                .filter(o -> Objects.equals(o.getPid(), CoreConstant.DEFAULT_ID))
                .collect(Collectors.toList());
        Map<Long, List<Menu>> childrenMenuGroup = menuList.stream()
                .filter(o -> !Objects.equals(o.getPid(), CoreConstant.DEFAULT_ID))
                .collect(Collectors.groupingBy(o -> o.getPid()));

        List<RoleLinkMenu> roleLinkMenuList = roleLinkMenuService.findByRoleId(id);
        Set<Long> roleMenuIds = roleLinkMenuList.stream().map(o -> o.getMenuId()).collect(Collectors.toSet());

        List<RoleMenuTree> roleMenuTreeList = new ArrayList<>();
        topList.forEach(o -> {
            List<RoleMenuTree> childrenRoleMenuTree = convertTree(roleMenuIds, o, childrenMenuGroup);
            // 子菜单有一个选中 或 当前自己被选中
            boolean checked = childrenRoleMenuTree.stream().anyMatch(c -> c.getChecked()) || roleMenuIds.contains(o.getId());
            RoleMenuTree roleMenuTree = new RoleMenuTree();
            roleMenuTree.setMenuId(o.getId());
            roleMenuTree.setMenuName(o.getName());
            roleMenuTree.setChecked(checked);
            roleMenuTree.setChildrenMenu(childrenRoleMenuTree);
            roleMenuTreeList.add(roleMenuTree);
        });
        return ResponseData.success(roleMenuTreeList);
    }

    /**
     * 转换树结构
     *
     * @param roleMenuIds
     * @param pMenu
     * @param childrenMenuGroup
     * @return
     */
    private static List<RoleMenuTree> convertTree(Set<Long> roleMenuIds, Menu pMenu, Map<Long, List<Menu>> childrenMenuGroup) {
        List<Menu> childrenMenu = childrenMenuGroup.getOrDefault(pMenu.getId(), Collections.emptyList());
        if (ObjectUtil.isEmpty(childrenMenu)) {
            return Collections.emptyList();
        }
        List<RoleMenuTree> roleMenuTreeList = new ArrayList<>();
        childrenMenu.forEach(o -> {
            List<RoleMenuTree> childrenRoleMenuTree = convertTree(roleMenuIds, o, childrenMenuGroup);
            // 子菜单有一个选中 或 当前自己被选中
            boolean checked = childrenRoleMenuTree.stream().anyMatch(c -> c.getChecked()) || roleMenuIds.contains(o.getId());
            RoleMenuTree roleMenuTree = new RoleMenuTree();
            roleMenuTree.setMenuId(o.getId());
            roleMenuTree.setMenuName(o.getName());
            roleMenuTree.setChecked(checked);
            roleMenuTree.setChildrenMenu(childrenRoleMenuTree);
            roleMenuTreeList.add(roleMenuTree);
        });
        return roleMenuTreeList;
    }


    @ApiOperation(value = "获取角色的资源勾选的菜单ID集合")
    @GetMapping("/{id}/menu/ids")
    public ResponseData<List<Long>> meneIdByRoleIdGet(@ApiParam(value = "角色ID") @PathVariable String id) {
        List<RoleLinkMenu> roleLinkMenuList = roleLinkMenuService.findByRoleId(id);
        return ResponseData.success(roleLinkMenuList.stream().map(o -> o.getMenuId()).collect(Collectors.toList()));
    }

}
